/*
 * @Author: your name
 * @Date: 2021-12-28 16:11:50
 * @LastEditTime: 2022-01-12 11:11:46
 * @LastEditors: your name
 * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * @FilePath: \vue\src\core\global-api\assets.js
 */
/* @flow */

import { ASSET_TYPES } from "shared/constants";
import { isPlainObject, validateComponentName } from "../util/index";

/**
 * 定义 Vue.component、Vue.filter、Vue.directive 这三个方法
 * 这三个方法所做的事情是类似的，就是在 this.options.xx 上存放对应的配置
 * 比如 Vue.component(compName, {xx}) 结果是 this.options.components.compName = 组件构造函数
 * ASSET_TYPES = ['component', 'directive', 'filter']
 */
export function initAssetRegisters(Vue: GlobalAPI) {
  /**
   * Create asset registration methods.
   */
  ASSET_TYPES.forEach((type) => {
    /**
     * 比如：Vue.component(name, definition)
     * @param {*} id name
     * @param {*} definition 组件构造函数或者配置对象
     * @returns 返回组件构造函数
     */

    Vue[type] = function (
      id: string,
      definition: Function | Object
    ): Function | Object | void {
      if (!definition) {
        return this.options[type + "s"][id];
      } else {
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== "production" && type === "component") {
          validateComponentName(id);
        }
        if (type === "component" && isPlainObject(definition)) {
          // 如果组件配置中存在 name，则使用，否则直接使用 id
          definition.name = definition.name || id;
          // extend 就是 Vue.extend，所以这时的 definition 就变成了 组件构造函数，使用时可直接 new Definition()
          definition = this.options._base.extend(definition);
        }
        if (type === "directive" && typeof definition === "function") {
          definition = { bind: definition, update: definition };
        }

        //在实例化时通过 mergeOptions 将全局注册的组件合并到每个组件的配置对象的 components 中
        // 比如 Vue.options.components.cmp={ }
        this.options[type + "s"][id] = definition;

        return definition;
      }
    };
  });
}
